package auction.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Timer;


import auction.domain.Auction;

import auction.domain.User;

public class Server {
	
	private static ArrayList<ClientThread> clients = new ArrayList<ClientThread>();
	private static ArrayList<User> users = new ArrayList<User>();
	private static ArrayList<Auction> auctions = new ArrayList<Auction>();
	private static int id = 0;
	
	static Timer timer = new Timer();

	/*
	 * main
	 */
	public static void main(String[] args) {
		/* check arguments */
		boolean correctArgs = args.length == 1 && args[0].matches("[0-9]+");
		int port = 0;

		if (correctArgs) {
			port = Integer.parseInt(args[0]);
			correctArgs = correctArgs && port > 0 && port < 65536;
		}
		else {
			System.err.println("Usage: java auction.server.Server <server port>");
			System.exit(1);
		}

		ServerSocket serverSocket = null;
		try {
			serverSocket = new ServerSocket(port);
		} catch (IOException e) {
			System.out.println("Could not bind to port " + port + " - "
					+ e.getMessage());
			System.exit(1);
		}

		while (true) {
			Socket socket;
			try {
				socket = serverSocket.accept();
			} catch (IOException e) {
				System.err
						.println("Could not listen for incoming connections - "
								+ e.getMessage());
				
				break;
			}
			ClientThread thread;
			try {
				thread = new ClientThread(socket);
				synchronized (clients) {
					clients.add(thread);
				}
				thread.start();
			} catch (IOException e1) {
				System.err.println("Incoming connection error - "
						+ e1.getMessage());
				try {
					socket.close();
				} catch (IOException e2) {
					/* ignore */
				}
			}
		}
	}

	/*
	 * if the client disconnects, the clientthread is removed from the clients list
	 */
	public static void removeClient(ClientThread thread) {
		synchronized (clients) {
			System.out.println("Client disconnected.");
			clients.remove(thread);
		}
	}
	/*
	 * if a new user logged in, the username is add to the users list
	 */
	public static void addUser(User user) {
		synchronized (users) {
			System.out.println("New User " + user.getUsername()
					+ " added.");
			users.add(user);
		}
	}
	/*
	 * if a user is already in the users list, only the boolean loggedIn is updated to true
	 */
	public static void setLoggedIn(String username) {
		synchronized (users) {
			for (User u : users) {
				
				if (u.getUsername().equals(username) ) {
					u.setLoggedIn(true);
					System.out.println("User "+username+" logged in.");
				}
			}
		}
		
	}
	/*
	 * if the user logs out, the boolean loggedIn needs to be set false
	 */
	public static void logoutUser(String username) {
		synchronized (users) {
			System.out.println("User "+username+" logged out.");
			
			for(User u : users){
				if (u.getUsername().equals(username)){
					u.setLoggedIn(false);
				}
			}
		}		
	}
	/*
	 * creates an auction by adding the action in the auctions list and schedule a timer with the specified time for the auction to last
	 */
	public static void createAuction(Auction auction, int time) {
		synchronized (auctions) {
			auctions.add(auction);
			timer.schedule(new AuctionTask(auction), time);
		}
	}
	/*
	 * bidding on an auction
	 */
	public static String bidAuction(String bidder, int id, double amount) {
		String ret="";
		synchronized (auctions) {
			for (Auction a : auctions) {
				
				if (a.getId()==id && !a.isEnded()) {
					if(amount>a.getHighestBid()){
						a.setHighestBid(amount);
						a.setHighestBidder(bidder);						
					}					
					ret=a.getHighestBidder()+";"+a.getHighestBid()+";"+a.getDescription();					
				}
				else if (a.getId()==id && a.isEnded())
					ret="ended";
			}
		}
		return ret;
	}
	/*
	 * generates the next auctionId
	 */
	public static int getNextAuctionId() {
		return id+=1;
	}
	/*
	 * if an auction is ended, the boolean ended from the auction has to be set true
	 */
	public static void endAuction(Auction auction) {
		synchronized (auctions) {
			for (Auction a : auctions) {
				
				if (a.getId()==auction.getId()) {
					a.setEnded(true);
				}
			}
			
		}
	}

	/*
	 * lists all active auctions
	 */
	public static String getAuctionList() {
		String ret = "";

		synchronized (auctions) {
			for (Auction auction : auctions) {
				if(!auction.isEnded())
					ret += auction.toString() + ";";
			}
		}

		if(ret.length()>1)
			return ret.substring(0, ret.length() - 1);
		else
			return ret;
	}

	/*
	 * returns true if the username is already in the userslist
	 */
	public static boolean usernameExists(String name) {
		synchronized (users) {
			for (User u : users) {
				
				if (u.getUsername().equals(name)) {
					return true;
				}
			}
		}
		return false;
	}
	/*
	 * returns true if the user is logged in
	 */
	public static boolean userLoggedIn(String username) {
		synchronized (users) {
			for (User u : users) {
				
				if (u.getUsername().equals(username) && u.isLoggedIn()) {
					return true;
				}
			}
		}
		return false;
	}

}
